MCP 클라이언트와 서버는 JSON 메시지를 교환하여 통신하지만, 이 메시지들은 실제로 어떻게 전송될까요? 사용되는 통신 채널을 전송(transport)이라고 하며, HTTP 요청부터 WebSocket, 심지어 엽서에 JSON을 쓰는 것까지 다양한 방법으로 구현할 수 있습니다(마지막 방법은 프로덕션에는 권장하지 않지만요).
Stdio 전송
MCP 서버나 클라이언트를 처음 개발할 때 가장 많이 사용되는 전송은 stdio 전송입니다. 이 방식은 간단합니다: 클라이언트가 MCP 서버를 하위 프로세스로 실행하고 표준 입출력 스트림을 통해 통신합니다.

작동 방식은 다음과 같습니다:
- 클라이언트가 서버의
stdin을 사용하여 서버에 메시지를 보냅니다
- 서버가
stdout에 작성하여 응답합니다
- 서버나 클라이언트 어느 쪽이든 언제든지 메시지를 보낼 수 있습니다
- 클라이언트와 서버가 같은 머신에서 실행될 때만 작동합니다
Stdio 동작 확인
별도의 클라이언트를 작성하지 않고도 터미널에서 직접 MCP 서버를 테스트할 수 있습니다. uv run server.py로 서버를 실행하면 stdin을 수신 대기하고 stdout으로 응답을 작성합니다. 즉, JSON 메시지를 터미널에 직접 붙여넣고 서버의 응답을 즉시 확인할 수 있습니다.
터미널 출력은 초기화 및 도구 호출의 예제 메시지를 포함한 전체 메시지 교환을 보여줍니다.
MCP 연결 시퀀스
모든 MCP 연결은 특정한 3개 메시지 핸드셰이크로 시작해야 합니다:

- Initialize Request - 클라이언트가 먼저 보냅니다
- Initialize Result - 서버가 기능 목록으로 응답합니다
- Initialized Notification - 클라이언트가 확인합니다 (응답 불필요)
이 핸드셰이크 후에만 도구 호출이나 프롬프트 목록과 같은 다른 요청을 보낼 수 있습니다.
메시지 유형과 흐름
MCP는 양방향으로 흐르는 다양한 메시지 유형을 지원합니다:

핵심은 일부 메시지는 응답이 필요하고(요청 → 결과) 다른 메시지는 필요하지 않다는 것입니다(알림). 클라이언트와 서버 모두 언제든지 통신을 시작할 수 있습니다.
네 가지 통신 시나리오
어떤 전송을 사용하든 네 가지 다른 통신 패턴을 처리해야 합니다:

- 클라이언트 → 서버 요청: 클라이언트가 stdin에 작성
- 서버 → 클라이언트 응답: 서버가 stdout에 작성
- 서버 → 클라이언트 요청: 서버가 stdout에 작성
- 클라이언트 → 서버 응답: 클라이언트가 stdin에 작성
stdio 전송의 장점은 간결함입니다 - 양쪽 모두 이 두 채널을 사용하여 언제든지 통신을 시작할 수 있습니다.
이것이 중요한 이유
stdio 전송을 이해하는 것이 중요한 이유는 양방향 통신이 원활한 "이상적인" 경우를 나타내기 때문입니다. HTTP와 같은 다른 전송으로 이동하면 서버가 항상 클라이언트에 요청을 시작할 수 없는 제한을 만나게 됩니다. stdio 전송은 기준점에서 다른 전송의 절충안을 이해하는 데 도움이 됩니다.
개발 및 테스트에는 stdio 전송이 완벽합니다. 클라이언트와 서버가 다른 머신에서 실행되어야 하는 프로덕션 배포에서는 각각의 절충안이 있는 다른 전송 옵션을 고려해야 합니다.